<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Timer;
use think\facade\Cache;
use think\facade\Config;

// 初始化ThinkPHP框架
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../config/app.php';

// 初始化应用
$app = new \think\App();
$app->initialize();

class GameServer
{
    private $worker;
    private $rooms = [];
    private $authenticatedUsers = [];

    public function __construct($port = 2346)
    {
        // 初始化缓存配置
        $this->initializeCache();
        
        $this->worker = new Worker("websocket://0.0.0.0:{$port}");
        
        // 调整进程数
        $this->worker->count = 4;
        
        // 设置每个进程最大连接数
        $this->worker->maxConnectionsPerWorker = 1000;
        
        // 心跳间隔
        $this->worker->pingInterval = 30;
        
        // 心跳数据
        $this->worker->pingData = '{"type":"ping"}';
        
        $this->worker->onWorkerStart = [$this, 'onWorkerStart'];
        $this->worker->onConnect = [$this, 'onConnect'];
        $this->worker->onMessage = [$this, 'onMessage'];
        $this->worker->onClose = [$this, 'onClose'];
    }

    private function initializeCache()
    {
        // 使用环境变量中的配置
        $cacheConfig = [
            'default' => env('CACHE.DRIVER', 'redis'),
            'stores' => [
                'redis' => [
                    'type' => 'redis',
                    'host' => env('CACHE.HOST', '127.0.0.1'),
                    'port' => env('CACHE.PORT', 6379),
                    'password' => env('CACHE.PASSWORD', ''),
                    'select' => env('CACHE.SELECT', 0),
                    'timeout' => 0,
                    'expire' => 0,
                    'persistent' => false,
                    'prefix' => '',
                ],
            ],
        ];

        Config::set($cacheConfig, 'cache');
    }

    public function onWorkerStart($worker)
    {
        echo "Game Server Started\n";
    }

    public function onConnect(TcpConnection $connection)
    {
        echo "New Connection\n";
        $connection->playerData = [
            'id' => uniqid(),
            'roomId' => null,
            'ready' => false,
            'isAuthenticated' => false,
            'username' => null,
            'token' => null
        ];
        $this->players[$connection->playerData['id']] = $connection;
    }

    public function onMessage(TcpConnection $connection, $data)
    {
        $message = json_decode($data, true);
        if (!$message || !isset($message['type'])) {
            return;
        }

        // 处理初始认证
        if ($message['type'] === 'authenticate') {
            $this->handleAuthentication($connection, $message);
            return;
        }

        // 验证token
        if (!isset($message['token'])) {
            $connection->send(json_encode([
                'type' => 'error',
                'message' => '请求参数缺token',
                'code' => 0
            ]));
            return;
        }

        // 验证token有效性
        $verificationResult = $this->verifyInternalToken($message['token']);
        if (!$verificationResult['valid']) {
            $connection->send(json_encode([
                'type' => 'error',
                'message' => '登录超时，请重新登录',
                'code' => -1
            ]));
            return;
        }

        switch ($message['type']) {
            case 'createRoom':
                $this->createRoom($connection);
                break;
            case 'joinRoom':
                $this->joinRoom($connection, $message['roomId']);
                break;
            case 'ready':
                $this->playerReady($connection);
                break;
            case 'gameAction':
                $this->handleGameAction($connection, $message['action']);
                break;
        }
    }

    private function getUserInfoFromToken($token)
    {
        try {
            if (empty($token)) {
                return null;
            }

            // 从缓存获取用户信息
            $cacheKey = 'user_token_' . $token;
            $userInfo = Cache::get($cacheKey);

            if (empty($userInfo)) {
                return null;
            }

            // 验证token是否过期
            if (!isset($userInfo['expire_time']) || $userInfo['expire_time'] < time()) {
                Cache::delete($cacheKey);
                return null;
            }

            return $userInfo;
        } catch (Exception $e) {
            $this->log("Get user info error: " . $e->getMessage());
            return null;
        }
    }

    private function verifyInternalToken($token)
    {
        try {
            if (empty($token)) {
                return ['valid' => false, 'username' => null];
            }

            // 使用内部方法获取用户信息
            $userInfo = $this->getUserInfoFromToken($token);
            
            if (empty($userInfo)) {
                return ['valid' => false, 'username' => null];
            }

            return [
                'valid' => true,
                'username' => $userInfo['nickname'] ?? $userInfo['username'] ?? 'unknown',
                'userInfo' => $userInfo
            ];
        } catch (Exception $e) {
            $this->log("Token verification error: " . $e->getMessage());
            return ['valid' => false, 'username' => null];
        }
    }

    private function handleAuthentication(TcpConnection $connection, $message)
    {
        if (!isset($message['token'])) {
            $connection->send(json_encode([
                'type' => 'error',
                'message' => '请求参数缺token',
                'code' => 0
            ]));
            return;
        }

        $token = $message['token'];
        $verificationResult = $this->verifyInternalToken($token);

        if ($verificationResult['valid']) {
            $username = $verificationResult['username'];
            $userInfo = $verificationResult['userInfo'];
            
            // 检查是否已经有相同用户登录
            if (isset($this->authenticatedUsers[$username])) {
                $oldConnection = $this->authenticatedUsers[$username];
                $oldConnection->send(json_encode([
                    'type' => 'error',
                    'message' => '账号在其他地方登录',
                    'code' => -1
                ]));
                $oldConnection->close();
            }

            $connection->playerData['isAuthenticated'] = true;
            $connection->playerData['username'] = $username;
            $connection->playerData['token'] = $token;
            $connection->playerData['userInfo'] = $userInfo;
            
            $this->authenticatedUsers[$username] = $connection;

            $connection->send(json_encode([
                'type' => 'authenticated',
                'username' => $username,
                'userInfo' => $userInfo
            ]));

            $this->log("User authenticated: " . $username);
        } else {
            $connection->send(json_encode([
                'type' => 'error',
                'message' => '登录超时，请重新登录',
                'code' => -1
            ]));
            $connection->close();
        }
    }

    public function onClose(TcpConnection $connection)
    {
        if (isset($connection->playerData)) {
            $playerId = $connection->playerData['id'];
            $roomId = $connection->playerData['roomId'];
            
            if ($connection->playerData['isAuthenticated']) {
                $username = $connection->playerData['username'];
                $token = $connection->playerData['token'];
                unset($this->authenticatedUsers[$username]);
            }
            
            if ($roomId && isset($this->rooms[$roomId])) {
                $this->leaveRoom($connection);
            }
            
            unset($this->players[$playerId]);
        }
    }

    private function createRoom(TcpConnection $connection)
    {
        $roomId = uniqid('room_');
        $this->rooms[$roomId] = [
            'id' => $roomId,
            'players' => [],
            'status' => 'waiting',
            'gameData' => null
        ];
        
        $this->joinRoom($connection, $roomId);
        
        $connection->send(json_encode([
            'type' => 'roomCreated',
            'roomId' => $roomId
        ]));
    }

    private function joinRoom(TcpConnection $connection, $roomId)
    {
        if (!isset($this->rooms[$roomId])) {
            $connection->send(json_encode([
                'type' => 'error',
                'message' => 'Room not found'
            ]));
            return;
        }

        if (count($this->rooms[$roomId]['players']) >= 4) {
            $connection->send(json_encode([
                'type' => 'error',
                'message' => 'Room is full'
            ]));
            return;
        }

        $connection->playerData['roomId'] = $roomId;
        $this->rooms[$roomId]['players'][$connection->playerData['id']] = $connection;

        $this->broadcastRoomState($roomId);
    }

    private function playerReady(TcpConnection $connection)
    {
        $roomId = $connection->playerData['roomId'];
        if (!$roomId || !isset($this->rooms[$roomId])) {
            return;
        }

        $connection->playerData['ready'] = true;
        $this->checkGameStart($roomId);
    }

    private function checkGameStart($roomId)
    {
        $room = $this->rooms[$roomId];
        $allReady = true;
        
        foreach ($room['players'] as $player) {
            if (!$player->playerData['ready']) {
                $allReady = false;
                break;
            }
        }

        if ($allReady && count($room['players']) >= 2) {
            $this->startGame($roomId);
        }
    }

    private function startGame($roomId)
    {
        $this->rooms[$roomId]['status'] = 'playing';
        $this->rooms[$roomId]['gameData'] = $this->initializeGameData();
        
        $this->broadcastRoomState($roomId);
    }

    private function handleGameAction(TcpConnection $connection, $action)
    {
        $roomId = $connection->playerData['roomId'];
        if (!$roomId || !isset($this->rooms[$roomId])) {
            return;
        }

        // 处理游戏动作逻辑
        // TODO: 实现具体的游戏规则
        
        $this->broadcastRoomState($roomId);
    }

    private function broadcastRoomState($roomId)
    {
        $room = $this->rooms[$roomId];
        $roomState = [
            'type' => 'roomState',
            'roomId' => $roomId,
            'status' => $room['status'],
            'players' => [],
            'gameData' => $room['gameData']
        ];

        foreach ($room['players'] as $player) {
            $roomState['players'][] = [
                'id' => $player->playerData['id'],
                'ready' => $player->playerData['ready']
            ];
        }

        foreach ($room['players'] as $player) {
            $player->send(json_encode($roomState));
        }
    }

    private function initializeGameData()
    {
        // 初始化游戏数据
        return [
            'currentTurn' => 0,
            'gameState' => []
        ];
    }

    public function run()
    {
        Worker::runAll();
    }

    private function log($message)
    {
        $time = date('Y-m-d H:i:s');
        echo "[$time] $message\n";
        // 或者写入日志文件
        file_put_contents(
            __DIR__ . '/game.log',
            "[$time] $message\n",
            FILE_APPEND
        );
    }

    private function leaveRoom(TcpConnection $connection)
    {
        $roomId = $connection->playerData['roomId'];
        if (!$roomId || !isset($this->rooms[$roomId])) {
            return;
        }

        // 从房间中移除玩家
        unset($this->rooms[$roomId]['players'][$connection->playerData['id']]);
        
        // 更新玩家数据
        $connection->playerData['roomId'] = null;
        $connection->playerData['ready'] = false;

        // 如果房间空了，删除房间
        if (empty($this->rooms[$roomId]['players'])) {
            unset($this->rooms[$roomId]);
            return;
        }

        // 如果游戏已经开始，可能需要处理游戏中断逻辑
        if ($this->rooms[$roomId]['status'] === 'playing') {
            $this->rooms[$roomId]['status'] = 'waiting';
            $this->rooms[$roomId]['gameData'] = null;
            
            // 重置所有玩家的准备状态
            foreach ($this->rooms[$roomId]['players'] as $player) {
                $player->playerData['ready'] = false;
            }
        }

        // 广播房间状态更新
        $this->broadcastRoomState($roomId);
    }
}

// 启动服务器
$server = new GameServer();
$server->run(); 